namespace Skymate.Commands
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;

    /// <summary>
    /// 方案调度
    /// </summary>
    public class SchedSolution
    {
        public const int BufferSize = 12;
        
        public int Month { get; set; }

        public int Day { get; set; }

        public int Week { get; set; }

        public int Hour { get; set; }

        public int Minute { get; set; }

        /// <summary>
        /// 方案号
        /// </summary>
        public int SolutionNo { get; set; }

        public static SchedSolution Create(byte[] buffer)
        {
            if (buffer.Length != BufferSize)
            {
                return null;
            }

            SchedSolution result = new SchedSolution
                                       {
                                           Month = GetMonth(buffer[1], buffer[0]),
                                           Day = GetDay(buffer[2], buffer[3], buffer[4], buffer[5]),
                                           Week = GetWeek(buffer[6]),
                                           Hour = buffer[7],
                                           Minute = buffer[8],
                                           SolutionNo = buffer[9]
                                       };
            
            return result;
        }

        public static int GetWeek(byte weekb)
        {
            // 0000 0001 表示周日 1
            // 0000 0010 表示周一 2
            // 0000 0100 表示周二 3
            var week = GetExponent(0x00, 0x00, 0x00, weekb);

            if (week == 1)
            {
                return 7;
            }

            return week - 1;
        }

        /// <summary>
        /// 获取日期,低位在前,高位在后
        /// </summary>
        /// <param name="b1"></param>
        /// <param name="b2"></param>
        /// <param name="b3"></param>
        /// <param name="b4"></param>
        /// <returns></returns>
        [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1616:ElementReturnValueDocumentationMustHaveText", Justification = "Reviewed. Suppression is OK here.")]
        public static int GetDay(byte b1, byte b2, byte b3, byte b4)
        {
            return GetExponent(b4, b3, b2, b1);
        }

        public static int GetMonth(byte high, byte low)
        {
            return GetExponent(0x00, 0x00, high, low);
        }
        
        /// <summary>
        /// 获取指数,传入的数据由高位 到低位
        /// </summary>
        /// <param name="value1">高2</param>
        /// <param name="value2">高1</param>
        /// <param name="value3">低2</param>
        /// <param name="value4">低1</param>
        /// <returns></returns>
        [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1616:ElementReturnValueDocumentationMustHaveText", Justification = "Reviewed. Suppression is OK here.")]
        public static int GetExponent(byte value1, byte value2, byte value3, byte value4)
        {
            var values = new[] { value4, value3, value2, value1 };
            var value = BitConverter.ToInt32(values, 0);
            if (value == 0)
            {
                return 0;
            }

            // 0000 0000 0000 0001 - 1 - 1 2的0次方
            // 0000 0000 0000 0010 - 2 - 2 2的1次方
            // 0000 0000 0000 0100 - 4 - 3 2的2次方
            // 0000 0000 0000 1000 - 8 - 4 2的3次方
            // 0000 0000 0001 0000 - 16 - 5 2的4次方
            var exponent = (int)Math.Log(value, 2);
            return exponent + 1;
        }

        public string[] ToStrings()
        {
            IList<string> result = new List<string>();

            result.Add(this.SolutionNo.ToString());
            result.Add(this.Month.ToString());
            result.Add(this.Day.ToString());
            result.Add(this.Week.ToString());
            result.Add(this.Hour.ToString());

            result.Add(this.Minute.ToString());

            return result.ToArray();
        }

        public byte[] ToBytes()
        {
            var result = new byte[12];

            var monthBuffer = BitConverter.GetBytes(this.Month);
            result[0] = monthBuffer[0];
            result[1] = monthBuffer[1];

            var dayBuffer = BitConverter.GetBytes(this.Day);
            result[2] = dayBuffer[0];
            result[3] = dayBuffer[1];
            result[4] = dayBuffer[2];
            result[5] = dayBuffer[3];

            if (this.Week == 7)
            {
                result[6] = 0x01;
            }
            else
            {
                result[6] = (byte)Math.Pow(2, this.Week);
            }

            result[7] = (byte)this.Hour;
            result[8] = (byte)this.Minute;
            result[9] = (byte)this.SolutionNo;

            return result;
        }
    }
}